package com.ricchieri.reports;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import javax.faces.context.FacesContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRAbstractExporter;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.data.JRAbstractBeanDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;

import com.ricchieri.common.BusinessSettings;
import com.ricchieri.util.FacesUtil;
import com.ricchieri.util.FileUtil;

/**
 * @author Andres Sacco
 *
 */
public abstract class ReportTemplate implements Serializable {
	
	private static final long serialVersionUID = 5104958866499625518L;
	
	private Logger log =  Logger.getLogger(this.getClass().getName());  

	private String reportName;
	private String reportFileName;
	private Date createDate;
	private ReportFileFormat reportFileFormat;
	
	protected abstract void addParameters(Map<String, Object> parameters);
	
	private String doWork(JRAbstractBeanDataSource dataSource) {
		
		log.info("Report Required:" + reportName);
		
		ServletOutputStream servletOutputStream = null;		

		try {
			String reportPath = FacesContext.getCurrentInstance().getExternalContext().getRealPath("/reports/" + reportName + ".jasper");  
			
			if(!FileUtil.existFile(reportPath)) {
				JasperCompileManager.compileReportToFile(FacesContext.getCurrentInstance().getExternalContext().getRealPath("/reports/" + reportName + ".jrxml"), FacesContext.getCurrentInstance().getExternalContext().getRealPath("/reports/" + reportName + ".jasper"));
			}

			Map<String, Object> parameters = new HashMap<String, Object>();
			
			parameters.put("contextRoot", FacesContext.getCurrentInstance().getExternalContext().getRealPath("/"));
			parameters.put(JRParameter.REPORT_LOCALE, FacesUtil.getLocale());
			parameters.put(JRParameter.REPORT_RESOURCE_BUNDLE, FacesUtil.getResourceBundle());
			addParameters(parameters);
			
			HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse(); 
			
			servletOutputStream = response.getOutputStream();
			
			JasperPrint jasperPrint = JasperFillManager.fillReport(reportPath, parameters, dataSource);
			
			switch (reportFileFormat) {
				case CSV:
					response.setContentType("text/csv");
					response.addHeader("Content-Disposition", "attachment;filename=" + reportFileName + ".csv");
					exportReportToCsv(jasperPrint, servletOutputStream);
					break;
	
				case PDF:
					response.setContentType("application/pdf");
					response.addHeader("Content-Disposition", "attachment;filename=" + reportFileName + ".pdf");
					exportReportToPdf(jasperPrint, servletOutputStream);
					break;
			}

			log.info("Report generated Successfully");
			return BusinessSettings.SUCCESS;
			
		} catch (JRException e) {
			e.printStackTrace();
			return BusinessSettings.UNSUCCESS;
		} catch (IOException e) {
			return BusinessSettings.UNSUCCESS;
		} finally {
			try {		
				servletOutputStream.flush();  
				servletOutputStream.close();
				FacesContext.getCurrentInstance().responseComplete();
			} catch (IOException e) {
				return BusinessSettings.UNSUCCESS;
			}
		}		
		
	}
	
	private void exportReportToPdf(JasperPrint jasperPrint, OutputStream outputStream) throws JRException {
		
		JRPdfExporter exporter = new JRPdfExporter();
		setCommonParameters(exporter, jasperPrint, outputStream);
		exporter.exportReport();
		
	}
	
	private void exportReportToCsv(JasperPrint jasperPrint, OutputStream outputStream) throws JRException {
		
		JRCsvExporter exporter = new JRCsvExporter();
		setCommonParameters(exporter, jasperPrint, outputStream);
		exporter.setParameter(JRExporterParameter.IGNORE_PAGE_MARGINS, true);
		exporter.setParameter(JRCsvExporterParameter.RECORD_DELIMITER, "\r\n");
		exporter.exportReport();
	}

	private void setCommonParameters(JRAbstractExporter exporter,
												JasperPrint jasperPrint,
												OutputStream outputStream) {

		exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
		exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);
		exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, BusinessSettings.REPORT_ENCODING);
	}
		
	protected void initReport(String reportType, ReportFileFormat fileFormat) {

		SimpleDateFormat formatDate = new SimpleDateFormat("mm-hh-dd-MM-yyyy");

		this.createDate = new Date(System.currentTimeMillis());
		this.reportFileName = reportType.concat("_").concat(formatDate.format(createDate));
		this.reportName = reportType;
		this.reportFileFormat = fileFormat;		
	}
	
	@SuppressWarnings("rawtypes") 
	protected String doWork(Collection data) {
		return doWork(new JRBeanCollectionDataSource(data));
	}

	protected String getReport() {
		return reportName;
	}
		
	protected ReportFileFormat getReportFileFormat() {
		return reportFileFormat;
	}

	public abstract void generateReport(Map<String,Object> map, ReportFileFormat reportFileFormat);

}
